const re0 = /^[0-9]*$/, re1 = /^[0-9]+$/

export function frac2dec(numS: string, denS: string) {
  if (!re1.test(numS) || !re1.test(denS)) throw null
  const num = BigInt(numS)
  const den = BigInt(denS)
  if (den === 0n) throw null

  const int = String(num / den)
  let rem = num % den
  let frac = ''
  const occurs = new Map<bigint, number>()

  for (; ;) {
    const idx = occurs.get(rem)
    if (idx != null) return {
      int,
      frac: frac.substring(0, idx),
      rep: frac.substring(idx),
    }
    occurs.set(rem, frac.length)

    rem *= 10n
    frac += String(rem / den)
    rem %= den
  }
}

export function dec2frac(intS: string, fracS: string, repS: string) {
  if (!re1.test(intS) || !re0.test(fracS) || !re0.test(repS)) throw null
  const int = BigInt(intS)
  const frac = BigInt(fracS)
  const rep = BigInt(repS)

  const fracDec = 10n ** BigInt(fracS.length)
  const repDec = rep === 0n ? 1n : 10n ** BigInt(repS.length) - 1n
  const den = repDec * fracDec
  const num = den * int + repDec * frac + rep
  const gcd = getGcd(num, den)
  return { num: String(num / gcd), den: String(den / gcd) }
}

function getGcd(a: bigint, b: bigint) {
  while (b !== 0n) [a, b] = [b, a % b]
  return a
}